package com.github.houkunlin.vo.impl;

import com.github.houkunlin.config.ConfigService;
import com.github.houkunlin.config.Settings;
import com.github.houkunlin.util.ProjectUtils;
import com.github.houkunlin.vo.IEntityField;
import com.github.houkunlin.vo.ITableColumn;
import com.google.common.collect.ImmutableMap;
import com.intellij.database.model.DasColumn;
import com.intellij.database.model.DataType;
import com.intellij.database.util.DasUtil;
import com.intellij.util.ReflectionUtil;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 数据库表字段信息（数据库表列对象信息）
 *
 * @author HouKunLin
 * @date 2020/5/28 0028 0:59
 */
@Getter
@ToString
public class TableColumnImpl implements ITableColumn {
    /**
     * 数据库表的原始字段对象
     */
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private final DasColumn dbColumn;
    private final String name;
    private final String comment;
    private final String typeName;
    private final DataType dataType;
    private final String jdbcType;
    private final String fullTypeName;
    private final boolean primaryKey;
    @Setter
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private IEntityField field;
    @Setter
    private boolean selected;

    private TableColumnImpl(
        String name, String typeName, String fullTypeName, String comment, boolean primaryKey, boolean selected){
        this.dbColumn = null;
        this.name = name;
        this.typeName = typeName;
        this.jdbcType = getJdbcType(this.typeName);
        this.dataType = null;
        this.fullTypeName = fullTypeName;
        this.comment = comment;
        this.primaryKey = primaryKey;
        this.selected = selected;
    }

    public TableColumnImpl(DasColumn dbColumn){
        this.dbColumn = dbColumn;
        this.name = dbColumn.getName();
        this.dataType = dbColumn.getDasType().toDataType();
        this.fullTypeName = dataType.getSpecification();
        this.typeName = ReflectionUtil.getField(DataType.class, dataType, String.class, "typeName");
        this.jdbcType = getJdbcType(this.typeName);
        this.comment = StringUtils.defaultString(dbColumn.getComment(), "");
        this.primaryKey = DasUtil.isPrimary(dbColumn);
        ConfigService configService = ConfigService.getInstance(ProjectUtils.getCurrProject());
        Optional<List<String>> ignoreFieldsOptional = Optional.ofNullable(configService).map(ConfigService::getSettings)
                                                              .map(Settings::getIgnoreFields);
        if(ignoreFieldsOptional.isPresent() && ignoreFieldsOptional.get().contains(dbColumn.getName())){
            this.selected = false;
        }else{
            this.selected = true;
        }
    }

    /**
     * 创建主键字段对象
     *
     * @param name         字段名称
     * @param typeName     字段类型
     * @param fullTypeName 字段完整类型
     * @param comment      字段注释
     * @return 字段对象
     */
    public static TableColumnImpl primaryColumn(String name, String typeName, String fullTypeName, String comment){
        ConfigService configService = ConfigService.getInstance(ProjectUtils.getCurrProject());
        boolean selected = true;
        Optional<List<String>> ignoreFieldsOptional = Optional.ofNullable(configService).map(ConfigService::getSettings)
                                                              .map(Settings::getIgnoreFields);
        if(ignoreFieldsOptional.isPresent() && ignoreFieldsOptional.get().contains(name)){
            selected = false;
        }
        return new TableColumnImpl(name, typeName, fullTypeName, comment, true, selected);
    }

    protected String getJdbcType(String typeName){
        typeName = typeName.trim().toLowerCase()
                           .replaceAll("unsigned","")
                           .replaceAll("zerofill","")
                           .trim();
        return jdbcTypeMap.getOrDefault(typeName.trim().toLowerCase(), typeName.toUpperCase());
    }

    @ToString.Exclude
    private Map<String, String> jdbcTypeMap = ImmutableMap.<String, String>builder().
             //整型
            put("tinyint", "TINYINT").
            put("integer", "INTEGER").
            put("smallint", "SMALLINT").
            put("mediumint", "INTEGER").
            put("int", "INTEGER").
            put("bigint", "BIGINT").
            //浮点
            put("real", "REAL").
            put("float", "FLOAT").
            put("double", "DOUBLE").
            //定点型
            put("numeric", "NUMERIC").
            put("decimal", "DECIMAL").
            //字符串
            put("char", "CHAR").
            put("varchar", "VARCHAR").
            put("tinytext", "VARCHAR").
            put("text", "VARCHAR").
            put("mediumtext", "LONGVARCHAR").
            put("longtext", "CLOB").
            //二进制
            put("binary", "BINARY").
            put("varbinary", "VARBINARY").
            put("bit", "BIT").
            put("tinyblob", "BLOB").
            put("blob", "BLOB").
            put("mediumblob", "BLOB").
            put("longblob", "BLOB").
            //时间
            put("time", "TIME").
            put("date", "DATE").
            put("datetime", "DATE").
            put("timestamp", "TIMESTAMP").build();
}
